package com.chesnutconsulting.otbasket.image.finder.artesia;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;

import org.apache.commons.lang.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.artesia.asset.Asset;
import com.artesia.asset.AssetIdentifier;
import com.artesia.asset.services.AssetDataLoadRequest;
import com.artesia.asset.services.AssetServices;
import com.artesia.common.exception.BaseTeamsException;
import com.artesia.entity.TeamsIdentifier;
import com.artesia.metadata.MetadataCollection;
import com.artesia.metadata.MetadataField;
import com.artesia.metadata.MetadataValue;
import com.artesia.metadata.services.MetadataServices;
import com.artesia.security.SecuritySession;
import com.chesnutconsulting.otbasket.image.finder.ImageFinder;
import com.google.common.base.Preconditions;

import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import com.google.common.base.Preconditions;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.HttpParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

//@Component
public class OtImageFinder implements ImageFinder {

//<<<<<<< HEAD
	private final OtBasketConfiguration otBasketConfiguration;
	private static final Logger LOGGER = LoggerFactory.getLogger(OtImageFinder.class);

//	@Inject
	public OtImageFinder(
			OtBasketConfiguration otBasketConfiguration) {
		this.otBasketConfiguration = otBasketConfiguration;
	}

	 
	public Map<String, String> getScalarMetadataForAsset(AssetIdentifier assetId) throws Exception {
		
		SecuritySession session = otBasketConfiguration.getSession();
		
		Map<String, String> assetMetadataMap = new LinkedHashMap<String, String>();
		
		AssetDataLoadRequest adlr = new AssetDataLoadRequest();
		adlr.setLoadAssetContentInfo(false);
		adlr.setLoadDestinationLinks(false);
		adlr.setLoadFPO(false);
		adlr.setLoadVocabularyTerms(false);
		adlr.setLoadMetadata(true);
		adlr.setLoadMetadataByModel(true);

		Asset asset = AssetServices.getInstance().retrieveAsset(assetId, adlr, session);
		if ( asset == null) 
		{
			LOGGER.info("Asset [{}] was not found for session [{}]", assetId.asString(), session.getLoginName());
			throw new BaseTeamsException ( "NONE.EXISTS", "Asset was not found" );
		}

		LOGGER.info("Current asset state {}", asset.getAssetState());
		MetadataCollection mdColl = asset.getMetadata();
		if (mdColl == null )
		{
			LOGGER.info("No metadata found for asset [{}] and session [{}]", assetId.asString(), session.getLoginName());
			return assetMetadataMap;
		}		

		List<TeamsIdentifier> fieldIdList = this.otBasketConfiguration.getScalarFieldList();
		for (TeamsIdentifier teamsIdentifier : fieldIdList) {
			MetadataValue mdValue = mdColl.getValueForField(teamsIdentifier);

			//TODO: move this logic to be loaded once at start of application
			System.out.println("Loading metadata for field [" + teamsIdentifier + "]");
			MetadataField[] fields = MetadataServices.getInstance().retrieveFieldsByIds(new TeamsIdentifier[]{teamsIdentifier}, session);
			String prompt = fields[0].getPrompt();

			if ( mdValue == null || StringUtils.isEmpty(mdValue.getStringValue()))
			{
				assetMetadataMap.put(prompt, "");
				System.out.println("Adding empty");
			}
			else
			{
				assetMetadataMap.put(prompt, mdValue.getStringValue());				
				System.out.println("Adding " + mdValue.getStringValue());
			}
		}
		
		return assetMetadataMap;
	}


	public OtBasketConfiguration getOtBasketConfiguration() {
		return otBasketConfiguration;
	}

	public String getScreenResImageUrl( String imageId )
	{
		return otBasketConfiguration.getBaseImageFetchUrl() + imageId;
	}
	/*
    public File getImage(String imageId) {
        HttpClient client = null;
        try {
            client = login();
            String imageUrl = otBasketConfiguration.getBaseImageFetchUrl() + imageId;
            HttpResponse imageResponse = fetchImage(imageUrl, client);

            Preconditions.checkArgument("image/jpeg".equalsIgnoreCase(
                    imageResponse.getEntity().getContentType().getValue()));
            return saveImageToDisk(imageId, imageResponse);
        } finally {
            if (client != null) {
                client.getConnectionManager().shutdown();
                /*
=======
	protected final OtBasketConfiguration basketConfiguration;

    private static final Logger LOGGER = LoggerFactory.getLogger(OtImageFinder.class);

    @Inject
    public OtImageFinder(OtBasketConfiguration basketConfiguration) {
        this.basketConfiguration = basketConfiguration;
        this.imageLoader = new ImageLoader();
    }

    @Override
    public Map<String, String> getScalarMetadataForAsset(AssetIdentifier assetId) throws Exception {
        SecuritySession session = basketConfiguration.getSession();

        Map<String, String> assetMetadataMap = new HashMap<String, String>();
        AssetDataLoadRequest adlr = new AssetDataLoadRequest();
        adlr.setLoadAssetContentInfo(false);
        adlr.setLoadDestinationLinks(false);
        adlr.setLoadFPO(false);
        adlr.setLoadVocabularyTerms(false);
        adlr.setLoadMetadata(true);
        adlr.setLoadMetadataByModel(true);

        Asset asset = getAssetServices().retrieveAsset(assetId, adlr, session);
        if ( asset == null)
        {
            LOGGER.info("Asset [{}] was not found for session [{}]", assetId.asString(), session.getLoginName());
            throw new BaseTeamsException ( "NONE.EXISTS", "Asset was not found" );
        }

        LOGGER.info("Current asset state {}", asset.getAssetState());
        MetadataCollection mdColl = asset.getMetadata();
        if (mdColl == null )
        {
            LOGGER.info("No metadata found for asset [{}] and session [{}]", assetId.asString(), session.getLoginName());
            return assetMetadataMap;
        }

        List<TeamsIdentifier> fieldIdList = this.basketConfiguration.getScalarFieldList();
        for (TeamsIdentifier teamsIdentifier : fieldIdList) {
            MetadataValue mdValue = mdColl.getValueForField(teamsIdentifier);
            if ( mdValue == null || StringUtils.isEmpty(mdValue.getStringValue()))
            {
                assetMetadataMap.put(teamsIdentifier.asString(), "");
                System.out.println("Adding empty");
            }
            else
            {
                assetMetadataMap.put(teamsIdentifier.asString(), mdValue.getStringValue());
                System.out.println("Adding " + mdValue.getStringValue());
>>>>>>> 31a54b969397281ed894a1de0e1e3dc0b1f035db

            }
        }

        return assetMetadataMap;
    }
*/
    protected AssetServices getAssetServices() {
        return AssetServices.getInstance();
    }


    protected final ImageLoader imageLoader = new ImageLoader();

    public File getImage(String imageId) {
        return imageLoader.getImage(imageId, getOtBasketConfiguration());
    }

    public List<File> getImages(Iterable<String> imageIds) {
        List<File> imageFiles = Lists.newArrayList();
        for(String id : imageIds) {
            imageFiles.add(getImage(id));
        }

        return imageFiles;
    }

    static class ImageLoader {
        
        public File getImage(String imageId, OtBasketConfiguration academyBasketConfiguration) {
            HttpClient client = null;
            try {

            	System.out.println("Logging in...");

                client = login(academyBasketConfiguration.getArtesiaServerUrl(),
                        academyBasketConfiguration.getArtesiaUser(),
                        academyBasketConfiguration.getArtesiaPwd());

                String imageUrl = academyBasketConfiguration.getBaseImageFetchUrl() + imageId;
                
            	System.out.println("Pulling image...");

                HttpResponse imageResponse = getResponse(imageUrl, client);

            	System.out.println("Got http response " + imageResponse.getStatusLine().getStatusCode());

                Preconditions.checkArgument("image/jpeg".equalsIgnoreCase(
                        imageResponse.getEntity().getContentType().getValue()));
            	System.out.println("Saving image to disk...");
                return saveImageToDisk(imageId, imageResponse, academyBasketConfiguration);
            } finally {
                if (client != null) {
                    client.getConnectionManager().shutdown();
                }
            }
        }

        File saveImageToDisk(String imageId, HttpResponse response, OtBasketConfiguration otBasketConfig) {
        	
        	System.out.println("Preparing output file " + imageId);

            File preparedFile = prepareOutputFile(imageId, otBasketConfig);
            try {
                InputStream inputStream = response.getEntity().getContent();
            	System.out.println("Reading in image ");
                BufferedImage image = ImageIO.read(inputStream);
            	System.out.println("Creating new file ");
                preparedFile.createNewFile();
            	System.out.println("Writing new image ");
                ImageIO.write(image, "jpg", preparedFile);
                return preparedFile;
            } catch (Throwable e) {
                LOGGER.error("Error while reading input from stream", e);
                throw new AssertionError("Error while reading input from stream");
            }
        }

        File prepareOutputFile(String imageId, OtBasketConfiguration otBasketConfig) {
            try {
                System.out.println("Preparing output file " + otBasketConfig.getTmpDir() + imageId + ".jpg");
                File file = new File(otBasketConfig.getTmpDir() + imageId + ".jpg");
                System.out.println("Prepared output file " + otBasketConfig.getTmpDir() + imageId + ".jpg");
                if (!file.getParentFile().exists()) {
                    LOGGER.debug("Adding output directory=%s", file.getParentFile().getPath());
                    
                    System.out.println("Directory did not exist, creating " + file.getParentFile().getPath());

                    file.getParentFile().mkdirs();

                    System.out.println("Created " + file.getParentFile().getPath());

                }

                return file;
            } catch (Throwable e) {
                LOGGER.error("Error while preparing output file", e);
                throw new AssertionError("Error while preparing Image download path.");
            }
        }

        static final HttpResponse getResponse(String url, HttpClient client) {
            try {
            	System.out.println("getting image " + url);
                HttpGet imageGet = new HttpGet(url);
            	System.out.println("prepped http get for image " + url);
                return client.execute(imageGet);
            } catch (Throwable e) {
            	e.printStackTrace();
                LOGGER.error("Could get an image response from {}", url, e);
                throw new AssertionError(String.format("Error getting image %s", url));
            }
        }

        HttpClient login(String loginUrl, String user, String credentials) {
            try {
                HttpClient client = new DefaultHttpClient();
                ClientConnectionManager mgr = client.getConnectionManager();
                HttpParams params = client.getParams();
                client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, 

                        mgr.getSchemeRegistry()), params);
                String urlWithParams = String.format(loginUrl, user, credentials);

                System.out.println("logging into system");
                HttpGet httpGet = new HttpGet(urlWithParams);
                client.execute(httpGet);
                System.out.println("logged into system");
                return client;
            } catch (Throwable e) {
            	System.out.println(e.getMessage());
            	e.printStackTrace();
                throw new AssertionError(String.format("Could not login to %s with user=%s", loginUrl, user));
            }
        }
    }
}
